package org.example.design.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.concurrent.TimeUnit;

/**
 * 请求切面日志
 */

@Slf4j  //打印日志
@Aspect //切面
@Component  //组件
public class WebLogAspect {

    @Resource
    ObjectMapper objectMapper;  //用于JSON反序列化

    @Pointcut("execution(public * org.example.design.Controller..*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void deBefore(JoinPoint joinPoint) throws Throwable{
        //1.获取HTTP请求
        ServletRequestAttributes attributes=(ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request=attributes.getRequest();
        //2.打印请求参数相关信息
        log.info("======================= Request Coming =======================");
        log.info("URL: [{}]",request.getRequestURL().toString());
        log.info("HTTP Method: [{}]",request.getMethod());
        //3.打印调用 controller 的全路径以及执行方法
        log.info("Class Method: [{}].[{}]",
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());
        //4.打印请求入参
        String requestArgs = objectMapper.writeValueAsString(joinPoint.getArgs());
        log.info("Request Args: [{}]",requestArgs);
    }

    @After("webLog()")
    public void doAfter()throws Throwable{
        log.info("======================= Request Done =======================");
        log.info("");
    }

    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        //通过这个来统计方法执行时间
        StopWatch stopWatch=StopWatch.createStarted();
        Object result=proceedingJoinPoint.proceed();
        String resultJson=objectMapper.writeValueAsString(result);
        log.info("Response Args: [{}]",resultJson);

        stopWatch.stop();
        log.info("Time Elapsed: [{}ms]",stopWatch.getTime(TimeUnit.MILLISECONDS));
        log.info("");
        return result;
    }
}
